package com.lagou;

import com.mapper.Mapper;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * @description: MiniCat 程序启动类
 * @author: yx
 * @date: 2021/8/31 17:42
 */
public class Bootstrap {

    //监听的端口号
    private int port = 8080;

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    private Map<String, HttpServlet> map = new HashMap<>();

    private Mapper mapper = new Mapper();

    /**
     * 程序启动方法
     *
     * @throws IOException
     */
    private void start() throws Exception {
        System.out.println("MiniCat start on port: " + port);
        ServerSocket serverSocket = new ServerSocket(port);

        //加载server.xml
        loadServer();
        //加载web.xml
        //loadServlet();

        //输出数据到页面
        /*while (true) {
            Socket socket = serverSocket.accept();
            OutputStream outputStream = socket.getOutputStream();
            String content = "Hello";
            content = HttpProtocolUtils.getHttpHeader200(content.getBytes().length) + content;
            outputStream.write(content.getBytes());
            InputStream inputStream = socket.getInputStream();
            Request request = new Request(inputStream);
            socket.close();
        }*/

        //静态资源输出
        /*while (true) {
            Socket socket = serverSocket.accept();
            InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream();

            //封装request和Response对象
            Request request = new Request(inputStream);
            Response response = new Response(outputStream);

            response.outputHtml(request.getUrl());

            socket.close();
        }*/

        //动态资源输出
/*        while (true) {
            Socket socket = serverSocket.accept();
            InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream();

            //封装request和Response对象
            Request request = new Request(inputStream);
            Response response = new Response(outputStream);

            HttpServlet httpServlet = map.get(request.getUrl());
            if (httpServlet == null) {
                //静态资源
                response.outputHtml(request.getUrl());
            }else {
                httpServlet.service(request, response);
            }
            socket.close();
        }*/


        //多线程版本
/*        while (true) {
            Socket socket = serverSocket.accept();
            MyThread myThread = new MyThread(socket, map);
            myThread.start();
        }*/

        int corePoolSize = 10;
        int maximumPoolSize = 50;
        long keepAliveTime = 100L;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(50);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
        //定义一个线程池
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                unit,
                workQueue,
                threadFactory,
                handler
        );

        //使用线程池
        while (true) {
            Socket socket = serverSocket.accept();
            //MyThread myThread = new MyThread(socket, map);
            MyMapperThread myMapperThread = new MyMapperThread(socket, mapper);
            threadPoolExecutor.execute(myMapperThread);
        }
    }

    /**
     * 加载server.xml获取appBase目录
     */
    private void loadServer() {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();//Server标签
            //获取所有的Host的标签
            List<Element> hostList = rootElement.selectNodes("//Host");
            for (Element element : hostList) {
                Mapper.MappedHost host = new Mapper.MappedHost();

                String hostName = element.attributeValue("name");
                //webapps的绝对路径
                String appBase = element.attributeValue("appBase");
                File appBaseFile = new File(appBase);
                File[] files = appBaseFile.listFiles();
                for (File file : files) {
                    //获取文件夹
                    if (file.isDirectory()) {
                        //封装Context
                        Mapper.MappedContext mappedContext = new Mapper.MappedContext();
                        //目录名
                        String contextName = file.getName();
                        mappedContext.setName(contextName);
                        //获取目录下的web.xml文件,并进行解析
                        File contextFile = new File(file, "web.xml");
                        List<Mapper.MappedWrapper> mappedWrapperList = loadWebXml(contextFile);
                        mappedContext.setExactWrappers(mappedWrapperList);
                        host.getContexts().add(mappedContext);
                    }
                }

                //设置hostName
                host.setName(hostName);
                mapper.getMappedHosts().add(host);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 解析web.xml
     *
     * @param contextFile
     * @return
     */
    private List<Mapper.MappedWrapper> loadWebXml(File contextFile) {
        List<Mapper.MappedWrapper> wrappers = new ArrayList<>();
        String absolutePath = contextFile.getAbsolutePath();
        try {
            InputStream resourceAsStream = new FileInputStream(absolutePath);
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();//web-app
            List<Element> selectNodes = rootElement.selectNodes("//servlet");
            for (Element element : selectNodes) {
                Mapper.MappedWrapper mappedWrapper = new Mapper.MappedWrapper();
                Element servletName = (Element) element.selectSingleNode("servlet-name");
                String servletNameValue = servletName.getStringValue();//lagou
                Element servletClass = (Element) element.selectSingleNode("servlet-class");
                String servletClassName = servletClass.getStringValue();//com.lagou.LagouServlet

                Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletNameValue + "']");
                String urlPatternValue = servletMapping.selectSingleNode("url-pattern").getStringValue();

                System.out.println("将urlPattern: " + urlPatternValue + " 和HttpServlet: " + servletClassName + "存入Map");
                //map.put(urlPatternValue, (HttpServlet) Class.forName(servletClassName).newInstance());
                mappedWrapper.setUrl(urlPatternValue);
                mappedWrapper.setServlet((HttpServlet) Class.forName(servletClassName).newInstance());
                wrappers.add(mappedWrapper);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return wrappers;
    }

    /**
     * 通过web.xml加载Servlet
     */
    private void loadServlet() {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("web.xml");
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();//web-app
            List<Element> selectNodes = rootElement.selectNodes("//servlet");
            for (Element element : selectNodes) {
                Element servletName = (Element) element.selectSingleNode("servlet-name");
                String servletNameValue = servletName.getStringValue();//lagou
                Element servletClass = (Element) element.selectSingleNode("servlet-class");
                String servletClassName = servletClass.getStringValue();//com.lagou.LagouServlet

                Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletNameValue + "']");
                String urlPatternValue = servletMapping.selectSingleNode("url-pattern").getStringValue();

                System.out.println("将urlPattern: " + urlPatternValue + " 和HttpServlet: " + servletClassName + "存入Map");
                map.put(urlPatternValue, (HttpServlet) Class.forName(servletClassName).newInstance());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Bootstrap bootstrap = new Bootstrap();
        try {
            //启动服务
            bootstrap.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
